package ssq.gamest.wolfmankill.port_windows;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

import net.sf.json.JSONObject;
import ssq.gamest.wolfmankill.Participant.Status;
import ssq.gamest.wolfmankill.WSClient;
import ssq.gamest.wolfmankill.WSServer;
import ssq.utils.StringUtils;
import ssq.utils.message_quene.Receiver;

public class MainActivity extends JFrame implements Receiver {
  public static final Font SongFont = new Font("宋体", Font.PLAIN, 21);
  private static final long serialVersionUID = 1;
  private LinkedList<JButton> participants = new LinkedList<JButton>();
  private JLabel statusLabel = new JLabel("等待连接");
  private JPanel playerListPane = new JPanel(new GridLayout(4, 4, 160, 160)), optionsPanel = new JPanel(new BorderLayout()), messagePanel = new JPanel(new GridBagLayout());
  private JTextArea chatContents = new JTextArea(3, 20), history = new JTextArea(30, 50);
  private JButton sendButton = new JButton("发送"), connectButton = new JButton("连接");
  private JComboBox<String> nameBox = new JComboBox<String>();
  private JTextField addressField = new JTextField(), portField = new JTextField(5);
  WSClient client;

  public WSClient getClient() {
    return client;
  }

  LinkedList<String> names = new LinkedList<String>();

  public JTextArea getChatContents() {
    return chatContents;
  }

  public void setChatContents(JTextArea chatContents) {
    this.chatContents = chatContents;
  }

  public JTextArea getHistory() {
    return history;
  }

  public void setHistory(JTextArea history) {
    this.history = history;
  }

  public JTextField getAddressField() {
    return addressField;
  }

  public void setAddressField(JTextField addressField) {
    this.addressField = addressField;
  }

  public List<String> getNames() {
    return names;
  }

  public void setNames(List<String> names) {
    this.names = new LinkedList<String>(names);
    resetPlayers();
  }

  public JComboBox<String> getNameBox() {
    return nameBox;
  }

  private void iniView() {
    setLayout(new BorderLayout());
    setLocation(100, 100);

    GridBagConstraints constraints = new GridBagConstraints();
    constraints.weightx = 1;
    constraints.weighty = 1;
    constraints.fill = GridBagConstraints.BOTH;
    constraints.anchor = GridBagConstraints.WEST;
    constraints.insets = new Insets(1, 1, 1, 1);
    constraints.ipadx = 3;
    constraints.ipady = 3;

    constraints.gridheight = 2;
    constraints.gridx = 0;
    chatContents.setAutoscrolls(true);
    chatContents.setFont(SongFont);
    messagePanel.add(new JScrollPane(chatContents), constraints);

    constraints.weightx = 0;
    constraints.fill = GridBagConstraints.NONE;
    constraints.gridheight = 1;
    constraints.gridx = 1;
    constraints.gridy = 0;
    messagePanel.add(nameBox, constraints);
    constraints.gridy = 1;
    messagePanel.add(sendButton, constraints);

    JPanel addressPanel = new JPanel(new FlowLayout());
    JLabel label = new JLabel("地址: ");
    label.setFont(SongFont);
    addressField.setFont(SongFont);
    portField.setFont(SongFont);
    connectButton.setFont(SongFont);
    addressField.setText("ws://localhost");
    portField.setText("44343");
    addressPanel.add(label);
    addressPanel.add(addressField);
    addressPanel.add(portField);
    addressPanel.add(connectButton);
    optionsPanel.add(addressPanel, BorderLayout.NORTH);
    optionsPanel.add(new JScrollPane(playerListPane), BorderLayout.CENTER);
    optionsPanel.add(messagePanel, BorderLayout.SOUTH);

    nameBox.setFont(SongFont);
    resetPlayers();

    add(optionsPanel, BorderLayout.CENTER);
    statusLabel.setFont(SongFont);
    add(statusLabel, BorderLayout.SOUTH);
    add(new JScrollPane(history), BorderLayout.EAST);
    history.setEditable(false);
    history.setFont(SongFont);
    pack();
  }

  static private MainActivity instance = new MainActivity();

  public static MainActivity getInstance() {
    return instance;
  }

  private MainActivity() {
    iniView();
    iniListeners();
    disableOption();
  }

  class MyMouseAdapter extends MouseAdapter {
    String helper;

    MyMouseAdapter(String helper) {
      this.helper = helper;
    }

    @Override
    public void mouseExited(MouseEvent e) {
      refreshState();
    }

    @Override
    public void mouseEntered(MouseEvent e) {
      statusLabel.setText(helper);
    }
  }

  public void disableReconnect() {
    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    connectButton.setEnabled(false);
    canReconnect = false;
  }

  public void enableReconnect() {
    canReconnect = true;
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    connectButton.setEnabled(true);
  }

  private void disableOption() {
    nameBox.setEnabled(false);
    sendButton.setEnabled(false);
    sendButton.removeMouseListener(sendAdapter);
    chatContents.removeKeyListener(sendShortcut);

    for (JButton button : participants) {
      button.setEnabled(false);
    }
  }

  boolean canReconnect = true;

  public void connect() {
    if (!canReconnect) {
      return;
    }

    if (client != null && client.isOpen()) {
      client.close();
    }

    String lastName = null;
    try {
      lastName = client.getMe().name;
    } catch (Exception e) {
    }

    try {
      String name = null;
      if (!StringUtils.noContent(lastName)) {
        name = lastName;
      } else {
        name = JOptionPane.showInputDialog("设置名字");
      }

      while (name == null || name.trim().length() == 0) {
        name = JOptionPane.showInputDialog("重新设置名字");
      }

      setTitle(name);
      client = new WSClient(new URI(addressField.getText() + ":" + portField.getText()), name);
      client.connect();
    } catch (URISyntaxException e1) {
      history.append("连接的格式不正确 : \n" + addressField.getText() + ":" + portField.getText());
    }
  }

  MyMouseAdapter connectMouseAdapter = new MyMouseAdapter("连接到指定服务器") {
    @Override
    public void mouseClicked(MouseEvent e) {
      connect();
    }

  }, sendAdapter = new MyMouseAdapter("给指定的玩家发送消息") {
    @Override
    public void mouseClicked(MouseEvent e) {
      sendMessage();
    };
  };

  KeyListener connectKeyAdapter = new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
      if (e.getKeyCode() == KeyEvent.VK_ENTER) {
        connect();
      }
    };
  };
  KeyAdapter sendShortcut = new KeyAdapter() {
    @Override
    public void keyPressed(KeyEvent e) {
      if (e.isControlDown() && e.getKeyCode() == KeyEvent.VK_ENTER) {
        sendMessage();
      }
    }
  };

  String constructMsg(String msg, String from, String to) {
    JSONObject tmp = JSONObject.fromObject(WSServer.constructMsg(msg, from));
    tmp.put("to", to);
    return tmp.toString();
  }

  private void iniListeners() {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    connectButton.addMouseListener(connectMouseAdapter);
    addressField.addKeyListener(connectKeyAdapter);
    portField.addKeyListener(connectKeyAdapter);
    chatContents.addKeyListener(sendShortcut);
  }

  private void sendMessage() {
    if (client != null && client.isOpen()) {
      String str = chatContents.getText();

      if (str.isEmpty()) {
        WSServer.sleepAWhile();
        return;
      }

      JSONObject msg = new JSONObject();
      msg.put("type", "msg");
      msg.put("to", nameBox.getSelectedItem().toString());
      msg.put("msg", str);

      client.send(msg.toString());

      chatContents.setText("");
    }
  }

  public static void main(String[] args) throws InterruptedException {
    getInstance().show();
  }

  public void appendMessage(String msg) {
    history.append(msg + '\n');
    history.setCaretPosition(history.getText().length());
  }

  public void resetPlayers() {
    playerListPane.removeAll();
    nameBox.removeAllItems();

    nameBox.addItem("all");
    for (String name : names) {
      JButton button = new JButton(name);
      button.setText(name);
      button.setBackground(Color.WHITE);
      button.setFont(SongFont);
      button.addMouseListener(participantMouseAdapter);
      participants.add(button);
      nameBox.addItem(name);

      playerListPane.add(button);
    }
    nameBox.removeItem("none");

    repaint();
  }

  public void refreshState() {
    if (client != null && client.getMe() != null && client.isOpen()) {
      statusLabel.setText("身份: " + client.getMe().role + "  状态: " + client.getMe().status + (client.getMe().isSergent ? " 警长" : ""));
    } else {
      statusLabel.setText("请重新连接服务器");
    }
  }

  public void reset() {
    client.getMe().forget();
    enableOption();
    names.clear();
    resetPlayers();
    refreshState();
    history.setText("");
  }

  private void enableOption() {
    nameBox.setEnabled(true);
    sendButton.setEnabled(true);
    sendButton.addMouseListener(sendAdapter);
    chatContents.addKeyListener(sendShortcut);

    for (JButton button : participants) {
      button.setEnabled(true);
    }
  }

  public void highlight(String msg) {
    for (JButton button : participants) {
      String name = button.getText().split("<-")[0];
      button.setText(name);
      button.setBackground(Color.WHITE);
    }

    if (msg != null && !msg.trim().equals("")) {
      List<String> entrys = Arrays.asList(msg.split(","));

      for (String entry : entrys) {
        String[] tmp = entry.split("=");

        for (JButton button : participants) {
          String name = button.getText().split("<-")[0];

          if (name.equals(tmp[1])) {
            button.setText(name + "<-" + tmp[0]);
            button.setBackground(Color.YELLOW);
          }
        }
      }
    }

    repaint();
  }

  MyMouseAdapter participantMouseAdapter = new MyMouseAdapter("投他的票或跟他聊天") {
    @Override
    public void mouseClicked(MouseEvent e) {
      JButton button = (JButton) e.getSource();
      if (button.isEnabled() && client.canVote) {
        client.send(WSServer.constructMessage("vote", button.getText().split("<-")[0]));
      }

      nameBox.setSelectedItem(((JButton) e.getSource()).getText());
      chatContents.requestFocus();
    }
  };

  public void shiver(String msg) {
    new Thread() {
      @Override
      public void run() {
        requestFocus();

        for (int i = 0; i < 3; i++) {
          shiverRound();
        }
      }
    }.start();

    appendMessage(msg);
  }

  static Point pos[] = new Point[32];

  static {
    for (int i = 0; i < 32; i++) {
      Point tmp = new Point((int) (10 * Math.sin(2 * Math.PI * i / 32)), (int) (10 * Math.cos(2 * Math.PI * i / 32)));
      pos[i] = tmp;
    }
  }

  private void shiverRound() {
    Point p = getLocation();
    int x = p.x;
    int y = p.y;

    for (int i = 0; i < 32; i++) {
      try {
        Thread.sleep(5);
      } catch (InterruptedException e) {
      }

      setLocation(x + pos[i].x, y + pos[i].y);
    }

    setLocation(p);
  }

  public void info(String msg) {
    JOptionPane.showMessageDialog(this, msg);
  }

  public void disableChat(String msg) {
    sendButton.removeMouseListener(sendAdapter);
    chatContents.removeKeyListener(sendShortcut);
  }

  public void enableChat() {
    sendButton.addMouseListener(sendAdapter);
    chatContents.addKeyListener(sendShortcut);
  }

  public void enable(String msg) {
    if (msg.equals("all")) {
      enableOption();
    } else {
      for (JButton button : participants) {
        if (msg.contains(button.getText())) {
          button.setEnabled(true);
        }
      }
    }
  }

  public void disable(String msg) {
    if (msg.equals("all")) {
      disableOption();
      client.getMe().status = Status.dead;
      refreshState();
    } else {
      for (JButton button : participants) {
        if (msg.contains(button.getText())) {
          button.setEnabled(false);
        }
      }
    }
  }

  public String toDetailedString() {
    try {
      StringBuilder sb = new StringBuilder((client == null) ? "" : client.toDetailedString());
      sb.append("\n names: ").append(names.toString());
      return sb.toString();
    } catch (Exception e) {
      return "";
    }
  }

  @Override
  public void consume(JSONObject msg) {
    client.dispatch(msg.toString());
  }

  public void sergent() {
    statusLabel.setText(statusLabel.getText().toString() + " 警长");
  }

  public void queryInfo(String msg) {
    JSONObject json = JSONObject.fromObject(msg);
    String hint = json.getString("hint");
    String backType = json.getString("backType");

    String result = JOptionPane.showInputDialog(hint);
    if (result == null) {
      result = "";
    }

    JSONObject resultJson = new JSONObject();

    resultJson.put("type", backType);
    resultJson.put("msg", result);

    client.send(resultJson.toString());
  }
}
